#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Ford UK NGc2 爬虫主模块
整合所有功能模块，实现完整的数据抓取流程
"""

import json
import os
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException

# 导入各功能模块
from .base import BaseWebDriver, PageUtilities
from .navigation import NavigationHandler, CookieHandler
from .drive_handler import DriveHandler
from .bodystyle_handler import BodystyleHandler
from .colour_handler import ColourHandler
from .interior_handler import InteriorHandler
from .extras_handler import ExtrasHandler
from .model_scraper import ModelScraper


class FordScraper:
    """Ford UK 网站爬虫主类 - 重构版"""
    
    def __init__(self, config):
        """
        初始化爬虫
        
        Args:
            config (dict): 配置信息
        """
        self.config = config
        
        # 初始化基础设施
        self.base_driver = BaseWebDriver()
        self.base_driver.setup_driver()
        
        # WebDriver实例和等待对象
        self.driver = self.base_driver.driver
        self.wait = self.base_driver.wait
        
        # 初始化工具类
        self.page_utilities = PageUtilities()
        
        # 初始化各功能模块
        self.navigation_handler = NavigationHandler(self.driver, self.wait)
        self.cookie_handler = CookieHandler(self.driver, self.wait)
        self.drive_handler = DriveHandler(self.driver, self.wait, self.navigation_handler)
        self.bodystyle_handler = BodystyleHandler(self.driver, self.wait, self.navigation_handler)
        self.colour_handler = ColourHandler(self.driver, self.wait, self.navigation_handler)
        self.interior_handler = InteriorHandler(self.driver, self.wait, self.navigation_handler)
        self.extras_handler = ExtrasHandler(self.driver, self.wait, self.navigation_handler)
        self.model_scraper = ModelScraper(self.driver, self.wait, self.page_utilities)
    
    def run(self):
        """主执行流程 - 集成车型选择和配置流程"""
        try:
            print("🚀 开始数据抓取流程...")
            
            # 第一阶段：基础页面加载和Cookie处理
            print("\n=== 第一阶段：页面初始化 ===")
            url = self.config['sub_model']['url']
            print(f"🌐 正在访问: {url}")
            self.driver.get(url)
            
            # 等待页面加载
            self.base_driver.wait_for_page_load()
            
            # 处理cookie同意弹窗
            self.cookie_handler.handle_cookie_consent()
            
            # 第二阶段：基础车型数据抓取
            print("\n=== 第二阶段：基础车型数据抓取 ===")
            car_series = self.model_scraper.scrape_model_data(self.config)
            
            # 从配置中获取目标车型名称（如果指定）
            target_model = None
            if hasattr(self, 'config') and self.config.get('target_model'):
                target_model = self.config.get('target_model')
            elif car_series.car_object_list:
                # 如果没有指定，默认选择第一个检测到的车型
                target_model = car_series.car_object_list[0].model_name
                print(f"🎨 未指定目标车型，默认选择: {target_model}")
            
            # 第三阶段：检测配置状态和数据抓取
            print("\n=== 第三阶段：配置状态检测和数据抓取 ===")
            
            # 检查是否已经在配置页面
            if self.navigation_handler.verify_configuration_entry():
                print("✅ 检测到已在配置页面，开始抓取配置数据")
                
                # 第四阶段：完整配置数据抓取
                print("\n=== 第四阶段：配置数据抓取 ===")
                if target_model:
                    enhanced_car_series = self.scrape_configuration_data(car_series, target_model)
                else:
                    print("⚠️  没有有效的目标车型，跳过配置数据抓取")
                    enhanced_car_series = car_series
                
                # 第五阶段：保存数据
                print("\n=== 第五阶段：保存数据 ===")
                self.save_data(enhanced_car_series)
            else:
                # 尝试传统的车型选择流程
                print("🔄 尝试传统车型选择流程...")
                
                if target_model:
                    # 选择车型并进入配置流程
                    config_success = self.select_model_and_enter_configuration(target_model)
                    
                    if config_success:
                        # 第四阶段：完整配置数据抓取
                        print("\n=== 第四阶段：配置数据抓取 ===")
                        enhanced_car_series = self.scrape_configuration_data(car_series, target_model)
                        
                        # 第五阶段：保存数据
                        print("\n=== 第五阶段：保存数据 ===")
                        self.save_data(enhanced_car_series)
                    else:
                        print("⚠️  未能进入配置流程，保存基础数据")
                        self.save_data(car_series)
                else:
                    print("⚠️  未找到有效的车型数据，保存基础数据")
                    self.save_data(car_series)
            
            print("🎉 数据抓取流程完成！")
            
        except Exception as e:
            print(f"❌ 执行过程中出现异常: {e}")
            raise
        finally:
            # 清理资源
            self.cleanup()
    
    def select_model_and_enter_configuration(self, target_model_name):
        """
        选择车型并进入配置流程
        
        Args:
            target_model_name (str): 目标车型名称
            
        Returns:
            bool: 是否成功进入配置流程
        """
        print(f"🎯 选择车型并进入配置: {target_model_name}")
        
        try:
            # 第一步：查找目标车型元素
            target_element = self.find_model_element(target_model_name)
            if not target_element:
                print(f"  ❌ 未找到车型: {target_model_name}")
                return False
            
            # 第二步：滚动到车型可见位置
            print(f"  📍 滚动到车型: {target_model_name}")
            self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", target_element)
            time.sleep(1)
            
            # 第三步：尝试点击车型进入配置流程
            success = self.click_model_to_configure(target_element, target_model_name)
            if not success:
                print(f"  ❌ 车型点击失败: {target_model_name}")
                return False
            
            # 第四步：验证是否成功进入配置流程
            if self.navigation_handler.verify_configuration_entry():
                print(f"  ✅ 成功进入 {target_model_name} 的配置流程")
                return True
            else:
                print(f"  ⚠️  车型点击了但未进入配置流程")
                
                # 尝试等待更长时间后再次验证
                print("  ⏳ 等待额外时间后再次验证...")
                time.sleep(5)
                if self.navigation_handler.verify_configuration_entry():
                    print(f"  ✅ 延迟验证成功，已进入 {target_model_name} 配置流程")
                    return True
                else:
                    return False
            
        except Exception as e:
            print(f"  ❌ 车型选择过程出错: {e}")
            return False
    
    def find_model_element(self, target_model_name):
        """查找指定名称的车型元素"""
        print(f"  🔍 查找车型元素: {target_model_name}")
        
        try:
            # 查找所有车型元素
            model_selectors = [
                f'div[data-cy="{target_model_name}"]',  # 精确匹配
                f'div[data-cy*="{target_model_name.lower()}"]',  # 包含匹配（小写）
                'div[data-cy][class*="ProductTile"]'  # 所有车型元素
            ]
            
            # 优先尝试精确匹配
            for i, selector in enumerate(model_selectors):
                try:
                    elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    
                    if i < 2:  # 精确匹配或包含匹配
                        for element in elements:
                            if element.is_displayed():
                                data_cy = element.get_attribute('data-cy')
                                if data_cy and (data_cy == target_model_name or 
                                              target_model_name.lower() in data_cy.lower()):
                                    print(f"    ✓ 找到匹配的车型元素: {data_cy}")
                                    return element
                    else:  # 遍历所有车型元素
                        for element in elements:
                            if element.is_displayed():
                                # 检查元素内容是否包含目标车型名
                                element_text = element.text.lower()
                                if target_model_name.lower() in element_text:
                                    print(f"    ✓ 通过文本匹配找到车型元素")
                                    return element
                except Exception:
                    continue
            
            print(f"    ❌ 未找到车型元素: {target_model_name}")
            return None
            
        except Exception as e:
            print(f"    ❌ 查找车型元素时出错: {e}")
            return None
    
    def click_model_to_configure(self, element, model_name):
        """点击车型进入配置"""
        print(f"    🖱️  点击车型进入配置: {model_name}")
        
        try:
            # 记录点击前的状态
            before_url = self.driver.current_url
            
            # 策略1：查找并点击配置按钮或整个卡片
            print("    🔍 查找配置按钮...")
            config_button_found = self.click_model_configuration_button(element, model_name)
            
            if config_button_found:
                time.sleep(3)
                after_url = self.driver.current_url
                
                print(f"    ✅ 配置按钮点击成功")
                print(f"      - 点击前URL: {before_url}")
                print(f"      - 点击后URL: {after_url}")
                
                # 不立即返回，让后续的验证函数决定
                return True
            
            # 策略2：如果第一种方法失败，尝试其他点击策略
            print("    🔄 尝试点击整个车型元素...")
            success = self.click_element_with_multiple_strategies(element, model_name)
            
            if success:
                time.sleep(3)
                after_url = self.driver.current_url
                print(f"    ✅ 车型元素点击成功")
                print(f"      - 点击前URL: {before_url}")
                print(f"      - 点击后URL: {after_url}")
                return True
            
            print(f"    ❌ 所有点击策略都失败")
            return False
            
        except Exception as e:
            print(f"    ❌ 点击车型时出错: {e}")
            return False
    
    def click_model_configuration_button(self, model_element, model_name):
        """点击车型的配置按钮或整个车型卡片"""
        try:
            # 策略1：查找配置相关的按钮
            button_selectors = [
                'button:contains("Select")',
                'button:contains("Configure")',
                'button:contains("Build")',
                'a:contains("Select")',
                'a:contains("Configure")',
                'button[class*="Select"]',
                'a[class*="Select"]'
            ]
            
            for selector in button_selectors:
                try:
                    buttons = model_element.find_elements(By.CSS_SELECTOR, selector)
                    for button in buttons:
                        if button.is_displayed() and button.is_enabled():
                            button_text = button.text.lower()
                            if any(keyword in button_text for keyword in ['select', 'configure', 'build']):
                                print(f"      ✓ 找到配置按钮: {button.text}")
                                self.base_driver.click_element_safely(button)
                                return True
                except Exception:
                    continue
            
            # 策略2：如果没有找到明确的按钮，点击整个车型卡片
            print(f"      🔄 未找到明确的配置按钮，尝试点击整个车型卡片...")
            
            # 尝试直接点击车型卡片
            try:
                self.driver.execute_script("arguments[0].click();", model_element)
                print(f"      ✓ 点击了整个车型卡片")
                return True
            except Exception as e:
                print(f"      ❌ 点击车型卡片失败: {e}")
                return False
            
        except Exception as e:
            print(f"      查找配置按钮时出错: {e}")
            return False
    
    def click_element_with_multiple_strategies(self, element, model_name):
        """使用多种策略点击元素"""
        try:
            strategies = [
                ("普通点击", lambda: element.click()),
                ("JavaScript点击", lambda: self.driver.execute_script("arguments[0].click();", element)),
                ("强制点击", lambda: self.driver.execute_script("""
                    arguments[0].dispatchEvent(new MouseEvent('click', {
                        view: window,
                        bubbles: true,
                        cancelable: true
                    }));
                """, element))
            ]
            
            for strategy_name, strategy_func in strategies:
                try:
                    print(f"      🎯 尝试{strategy_name}...")
                    strategy_func()
                    time.sleep(1)
                    return True
                except Exception as e:
                    print(f"      {strategy_name}失败: {e}")
                    continue
            
            return False
            
        except Exception as e:
            print(f"      多策略点击失败: {e}")
            return False
    
    def scrape_configuration_data(self, car_series, target_model):
        """抓取配置数据的协调方法"""
        print("🔧 开始抓取完整配置数据...")
        
        try:
            # 步骤1：进入Drive页面并抓取Drive数据
            print("  🚗 抓取Drive数据...")
            drive_data = self.drive_handler.scrape_drive_data()
            
            if drive_data:
                print(f"  🎯 找到 {len(drive_data)} 个真正的Drive选项")
                
                # 步骤2：根据新业务逻辑，为每个Drive创建独立的CarObject
                self.drive_handler.update_car_objects_with_drive_data(car_series, target_model, drive_data)
                
                # 步骤3：循环每个Drive选项，进入Bodystyle页面
                print("  🎨 开始循环Drive类型抓取Bodystyle数据...")
                all_bodystyle_data = self.bodystyle_handler.scrape_bodystyle_for_all_drives(drive_data)
                
                # 将Bodystyle数据添加到对应的CarObject中
                if all_bodystyle_data:
                    self.bodystyle_handler.update_car_objects_with_bodystyle_data(car_series, target_model, all_bodystyle_data)
            else:
                print("  ⚠️  未找到有效的Drive选项，跳过Bodystyle抓取")
            
            # 步骤4：进入Colour页面并滚动抓取
            print("  🌈 抓取Colour数据...")
            colour_data = self.colour_handler.scrape_colour_data()
            
            if colour_data:
                self.colour_handler.update_car_objects_with_colour_data(car_series, target_model, colour_data)
            
            # 步骤5：进入Interior页面并抓取
            print("  🛋️ 抓取Interior数据...")
            interior_data = self.interior_handler.scrape_interior_data()
            
            if interior_data:
                self.interior_handler.update_car_objects_with_interior_data(car_series, target_model, interior_data)
            
            # 步骤6：进入Extras页面并抓取
            print("  🔧 抓取Extras数据...")
            extras_data = self.extras_handler.scrape_extras_data()
            
            if extras_data:
                self.extras_handler.update_car_objects_with_extras_data(car_series, target_model, extras_data)
            
            print("✅ 完整配置数据抓取完成")
            return car_series
            
        except Exception as e:
            print(f"❌ 抓取配置数据时出错: {e}")
            return car_series
    
    def save_data(self, car_series):
        """保存数据到文件"""
        try:
            print("💾 保存数据到文件...")
            
            # 确保输出目录存在
            output_dir = "./release"
            os.makedirs(output_dir, exist_ok=True)
            
            # 保存到指定文件
            output_file = self.config['sub_model']['output_file']
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(car_series.toJSONString())
            
            print(f"✅ 数据已保存到: {output_file}")
            
            # 同时保存一份到默认位置
            default_output = os.path.join(output_dir, "output.json")
            with open(default_output, 'w', encoding='utf-8') as f:
                f.write(car_series.toJSONString())
            
            print(f"✅ 数据副本已保存到: {default_output}")
            
        except Exception as e:
            print(f"❌ 保存数据时出错: {e}")
    
    def cleanup(self):
        """清理资源"""
        try:
            print("🧹 清理资源...")
            self.base_driver.cleanup()
        except Exception as e:
            print(f"清理资源时出错: {e}")


# 为了保持向后兼容性，保留一些原有的方法接口
class FordScraperLegacy(FordScraper):
    """保持向后兼容的接口类"""
    
    def setup_driver(self):
        """向后兼容的driver setup方法"""
        return self.base_driver.setup_driver()
    
    def wait_for_page_load(self):
        """向后兼容的页面等待方法"""
        return self.base_driver.wait_for_page_load()
    
    def handle_cookie_consent(self):
        """向后兼容的Cookie处理方法"""
        return self.cookie_handler.handle_cookie_consent()
    
    def click_element_safely(self, element):
        """向后兼容的安全点击方法"""
        return self.base_driver.click_element_safely(element)